package by.sjc.giz.service.orders;

import by.sjc.giz.dao.converters.OrderConverter;
import by.sjc.giz.dao.entity.OrderEntity;
import by.sjc.giz.dao.repositiory.OrderDao;
import by.sjc.giz.model.Order;
import by.sjc.giz.model.OrderRecord;
import by.sjc.giz.model.OrderStatus;
import by.sjc.giz.service.PaymentService;
import by.sjc.giz.service.ShopService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * Created by Z on 18.08.14.
 */
@Component
public class ShopOrderProcessor implements RecipientOrderProcessor, SenderOrderProcessor {

    public static final Logger logger = Logger.getLogger(ShopOrderProcessor.class);

    @Autowired
    private ShopService shopService;
    @Autowired
    private OrderConverter orderConverter;
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private PaymentService paymentService;

    @Override
    public void addOrder(Order order) {
        logger.info(order.toString());
        OrderEntity orderEntity = orderConverter.convertToOrderEntity(order);
        orderDao.save(orderEntity);
    }

    @Override
    /**
     * @return returns true, if something changed.
     */
    public boolean confirmIncomingOrder(Order order) {
        switch (order.getState()) {
            case NEW : {
                if ( ! handleNewOrder(order) )
                    return false;
                break;
            }
            case SENDER_CANCELED: {
                if ( ! handleSenderCanceledOrder(order))
                    return false;
                break;
            }
            case WAITING_FOR_BOOK_RELEASES: {
                if ( ! handleWaitingForBookReleasesOrder(order))
                    return false;
                break;
            }
            case WAITING_FOR_RECIPIENT_FEASIBILITY: {
                if ( ! handleWaitingForRecipientFeasibilityOrder(order))
                    return false;
                break;
            }
            case WAITING_FOR_PAY: {
                if ( ! handleWaitingForPayOrder(order))
                    return false;
                break;
            }
            default: return false;
        }

        OrderEntity orderEntity = orderConverter.convertToOrderEntity(order);
        orderEntity.setChangeDate(new Date());
        orderDao.saveOrUpdate(orderEntity);
        return true;
    }

    @Override
    public boolean  confirmOutgoingOrder(Order order) {
        switch (order.getState()) {
            case PAYED: {
                shopService.addBooksToStore(order.getSender().getId(), order.getRecords());
                order.setState(OrderStatus.SATISFIED);
                break;
            }
            case RECIPIENT_REJECTED: {
                order.setState(OrderStatus.ABORTIVE);
                break;
            }
            default:
                return false;
        }//switch

        OrderEntity orderEntity = orderConverter.convertToOrderEntity(order);
        orderEntity.setChangeDate(new Date());
        orderDao.saveOrUpdate(orderEntity);
        return true;
    }



    private boolean handleNewOrder(Order order) {
        if (order.getIsPreorder()) {
            order.setState(OrderStatus.WAITING_FOR_BOOK_RELEASES);
        } else if ( shopService.canSatisfyOrder( order.getRecipient().getId(), order.getRecords() ) ) {
            handleWaitingForPayOrder(order);
        } else {
            order.setState(OrderStatus.WAITING_FOR_RECIPIENT_FEASIBILITY);
        }
        return true;
    }

    private boolean handleSenderCanceledOrder(Order order) {
        order.setState(OrderStatus.ABORTIVE);
        return true;
    }

    private boolean handleWaitingForBookReleasesOrder(Order order) {
        if ( order.getIsPreorder() ) {
            return false;
        } else {
            //order is released. so checking the payment
            if ( ! shopService.canSatisfyOrder( order.getRecipient().getId(), order.getRecords() ) ) {
                order.setState(OrderStatus.WAITING_FOR_RECIPIENT_FEASIBILITY);
            } else {
                //requesting payment
                paymentService.paymentRequest(order.getPayment(), order.getCost());
                //checking
                handleWaitingForPayOrder(order);
            }
        }
        return true;
    }

    private boolean handleWaitingForRecipientFeasibilityOrder(Order order) {
        if ( shopService.canSatisfyOrder( order.getRecipient().getId(), order.getRecords() ) ) {
            //requesting payment
            paymentService.paymentRequest(order.getPayment(), order.getCost());
            //checking payment
            handleWaitingForPayOrder(order);
            return true;
        } else {
            return false;
        }
    }

    private boolean handleWaitingForPayOrder(Order order) {
        if ( shopService.canSatisfyOrder( order.getRecipient().getId(), order.getRecords() ) ) {
            switch (paymentService.checkPaymentStatus(order.getPayment())) {
                case DENIED:
                    order.setState(OrderStatus.RECIPIENT_REJECTED);
                    break;
                case PAYED:
                    shopService.removeFromStore(order.getRecipient().getId(), order.getRecords());
                    order.setState(OrderStatus.PAYED);
                    break;
                case WAITING_FOR_USER:
                    order.setState(OrderStatus.WAITING_FOR_PAY);
                    return false;
            }
            return true;
        } else {
            //do nothing =). We can't satisfy order, but client may have payed.
            order.setState(OrderStatus.WAITING_FOR_PAY);
            return false;
        }
    }




}
